<template>
  <div
    v-show="isOpen"
    class="popup-dialog"
    ref="popupDialog"
    :class="{ close: closeAnim }"
    @click.self="isSelection && close()"
    @animationend.self="animationEnd"
  >
    <div v-if="!isSelection" class="box bg-surface" :style="{ transform: boxTransform }">
      <div v-if="image !== null" class="image">
        <div class="bg primary-gradient">
          <Avatar :src="image" :radius="40" :vip="isPremium"></Avatar>
        </div>
      </div>
      <div v-if="title" class="title font-size-16 font-weight-500 line-height-140" :class="{ 'mb-shrink': !!subtitle }">
        {{ title }}
      </div>
      <div v-if="subtitle" class="subtitle">{{ subtitle }}</div>
      <div class="content" ref="contentRef">
        <keep-alive :max="5">
          <component :is="component"></component>
        </keep-alive>
      </div>
      <div
        v-if="actions?.cancel || showConfirm || buttonSlot"
        class="btns"
        :class="[buttonSlot ? `gap-col-16 flex-col` : `gap-row-8 flex-row`]"
      >
        <button
          v-if="actions?.cancel"
          class="cancel cancel-btn"
          :class="{ 'bg-gray-x': cancelLightTheme }"
          @click="cancel"
        >
          {{ texts?.cancel }}
        </button>
        <button
          v-if="showConfirm"
          class="confirm primary-btn"
          :class="{ 'primary-gradient': confirmGradient }"
          :disabled="confirmDisabled"
          style="min-width: 7.75rem"
          @click="checkCustomContentData"
        >
          <CircularLoading
            v-if="confirmDisabled"
            size="20"
            weight="2.5"
            color="grayscale"
            duration="1"
            type="solid"
          ></CircularLoading>
          <span v-else>{{ texts?.confirm }}</span>
        </button>
        <div v-if="buttonSlot">
          <component :is="buttonSlot.component" v-bind="buttonSlot.props" @click="buttonSlot.callback"></component>
        </div>
      </div>
      <div v-if="remarkSlot" class="remark">
        <component :is="remarkSlot.component" v-bind="remarkSlot.props" @click="remarkSlot.callback"></component>
      </div>
      <div v-if="showBack" class="back pointer" @click="backCallback"><Icon size="24" name="back"></Icon></div>
      <div v-if="showClose" class="close pointer" @click="close">
        <Icon size="24" name="close"></Icon>
      </div>
    </div>
    <div v-else class="box selection bg-surface" :style="{ transform: boxTransform }">
      <div v-for="(item, i) in content" :key="item" @click="confirm(i)">
        <div class="option font-size-14 font-weight-500 line-height-140 text-center pointer">{{ item }}</div>
        <div class="divider" v-if="i < content.length - 1"></div>
      </div>
    </div>
  </div>
</template>

<script setup>
import { computed, ref, watch } from 'vue'
import { storeToRefs } from 'pinia'
import { usePopupDialogStore } from '@/store/popup-dialog'
import Avatar from '@/components/multimedia/Avatar.vue'
import { useEnterPosition } from '@/compositions/dialog/enter-position'
import { usePreventTouchmove } from '@/compositions/mobile/preventTouchmove'
import { NO_DATA_POPUP_DIALOG } from '@/constant'
import CircularLoading from '../common/CircularLoading.vue'
import contentComponent from './content'

// 關閉動畫
const closeAnim = ref(false)

// 彈窗 transform style
const boxTransform = ref('')

const popupDialogStore = usePopupDialogStore()
const {
  isOpen,
  isSelection,
  isPremium,
  type,
  image,
  title,
  subtitle,
  content,
  fromCenter,
  actions,
  texts,
  cancelLightTheme,
  confirmGradient,
  showClose,
  showConfirm,
  showBack,
  buttonSlot,
  remarkSlot,
  closeCallback,
  backCallback,
  confirmDisabled,
} = storeToRefs(popupDialogStore)
const { openNext: openNextPopupDialog, close: closePopupDialog, setInputData, setConfirmData } = popupDialogStore

const { x, y } = useEnterPosition()

watch(isOpen, (v) => {
  if (v) {
    boxEnter()
  }
})

const component = computed(() => {
  return contentComponent[type.value]
})

function checkCustomContentData() {
  if (NO_DATA_POPUP_DIALOG.includes(type.value)) {
    confirm()
  } else {
    setConfirmData((data) => {
      console.log('setConfirmData', data)
      if (data !== false) confirm(data)
      else confirmDisabled.value = false
    })
  }
}

async function confirm(data) {
  const fn = actions.value.confirm
  if (fn) {
    confirmDisabled.value = true
    try {
      await fn(data)
    } catch (e) {
      console.warn(e)
      return
    } finally {
      confirmDisabled.value = false
    }
  }

  // 將資料儲存起來，供後續串連彈窗可以取得使用
  setInputData(data)

  // 嘗試開啟下一個串連彈窗
  // 回傳 false 表示沒有下一個，直接關閉
  if (!openNextPopupDialog(data)) {
    close()
  }
}

function cancel() {
  const fn = actions.value.cancel
  if (fn) {
    const cancelResult = fn()
    if (typeof cancelResult === 'boolean' && !cancelResult) {
      return
    }
  }

  close()
}

function close() {
  if (closeCallback.value) closeCallback.value()
  boxLeave()
  closeAnim.value = true
}

function animationEnd(evt) {
  if (evt.animationName.startsWith('fade-out')) {
    closePopupDialog()
    closeAnim.value = false
    closeCallback.value = null
  }
}

function boxEnter() {
  boxTransition(true)
}

function boxLeave() {
  boxTransition()
}

function boxTransition(enter) {
  const xv = fromCenter.value ? 0 : x.value
  const yv = fromCenter.value ? 0 : y.value
  const sv = 0
  boxTransform.value = `translate(${xv}px, ${yv}px) scale(${sv})`

  if (enter) {
    requestAnimationFrame(() => (boxTransform.value = ''))
  }
}

const popupDialog = ref(null)
const contentRef = ref(null)

usePreventTouchmove(popupDialog, (evt) => {
  let currEle = evt.target
  while (true) {
    if (currEle === contentRef.value) {
      return false
    }
    if (currEle === popupDialog.value) {
      return true
    }
    currEle = currEle.parentElement
  }
})
</script>

<style lang="scss" scoped>
@keyframes fade-in {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
@keyframes fade-out {
  0% {
    opacity: 1;
  }
  100% {
    opacity: 0;
  }
}

.popup-dialog {
  width: 100%;
  height: 100%;
  background-color: rgba(0, 0, 0, 0.3);
  position: fixed;
  top: 0;
  left: 0;
  display: flex;
  justify-content: center;
  align-items: center;
  animation: fade-in 0.3s;

  z-index: 3000;

  &.close {
    animation: fade-out 0.3s 0.2s;
  }

  .box {
    width: 75%;
    max-width: 17.5rem;
    padding: 0.75rem 1rem 1rem;
    border-radius: 0.625rem;
    position: relative;
    transition: transform 0.3s ease-out;
    transform-origin: center;

    .image {
      height: 2.75rem;
      transform: translateY(-3.125rem);
      .bg {
        width: 5.125rem;
        height: 5.125rem;
        margin: auto;
        border-radius: 5.125rem;
        margin-bottom: 1rem;
        display: flex;
        justify-content: center;
        align-items: center;
      }
    }

    .title {
      margin-bottom: 1rem;
      text-align: center;
    }

    .mb-shrink {
      margin-bottom: 0.25rem;
    }

    .subtitle {
      margin-bottom: 1rem;
      text-align: center;

      font-size: 0.75rem;
      font-style: normal;
      font-weight: 400;
      line-height: 120%;

      color: var(--color-text-disabled-gray, #d7d7d7);
    }

    .btns {
      padding-top: 1rem;
      display: flex;
      .confirm,
      .cancel {
        flex-grow: 1;
      }
    }

    .back,
    .close {
      width: 1.25rem;
      height: 1.25rem;
      position: absolute;
      top: 0.5rem;
    }

    .back {
      left: 0.75rem;
    }
    .close {
      top: 0.5rem;
      right: 0.75rem;
    }

    &.selection {
      padding: 0 1rem;

      .option {
        padding: 1rem 0;
      }
      .divider {
        height: 1px;
        background: rgba(215, 215, 215, 0.4);
      }
    }

    .remark {
      margin-top: 1rem;
      display: flex;
      justify-content: center;
    }
  }
}
</style>
